package com.biscuit.page.basicservice.design.verify_code.publish.strategy;

import com.biscuit.page.basicservice.bean.RedisCache;
import com.biscuit.page.basicservice.design.verify_code.publish.VerifyCodePublishAbstractDTO;
import com.biscuit.page.basicservice.design.verify_code.publish.VerifyCodePublishContext;
import com.biscuit.page.basicservice.utils.BaseExceptionUtil;
import com.biscuit.page.basicservice.utils.RegexUtil;
import com.biscuit.page.basicservice.utils.VerifyCodeUtil;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @author biscuit
 * @createTime 2024/6/25 11:19
 */
@Component
public abstract class AbstractVerifyCodePublishStrategy implements VerifyCodePublishStrategy {

    @Resource
    private RedisCache redisCache;

    public abstract void publish(VerifyCodePublishContext context);

    public VerifyCodePublishAbstractDTO publishBefore(VerifyCodePublishContext context) {
        // 校验账号格式是否非法
        boolean validateEmail = RegexUtil.validateEmail(context.getAccount());
        boolean validateMobile = RegexUtil.validateMobile(context.getAccount());
        BaseExceptionUtil.throwException(validateMobile || validateEmail, "账号格式错误");

        // 组装 ip 发送次数缓存 key
        String ipCountKey = "verify_code:ip_count:" + context.getIp();

        // 从缓存中获取指定 ip 的发送次数
        Integer ipCount = this.redisCache.get2Integer(ipCountKey);

        // 校验同一 ip 在 24 小时内的发送次数是否大于阈值
        BaseExceptionUtil.throwException(ipCount < 21, "操作过于频繁，请稍后重试");

        // 组装验证码相关数据的缓存 key
        String publishCountKey = VerifyCodeUtil.getVerifyPublishCountKey(context.getPrefix(), context.getAccount());
        String verifyCodeKey = VerifyCodeUtil.getVerifyCodeKey(context.getPrefix(), context.getAccount());

        // 从缓存中获取指定 account 的发送次数
        Integer publishCount = this.redisCache.get2Integer(publishCountKey);

        // 校验同一 account 与 业务，在 1 小时内的发送次数是否大于阈值
        BaseExceptionUtil.throwException(publishCount < 5, "操作过于频繁，请稍后重试");

        // 设置内置 dto 对象
        VerifyCodePublishAbstractDTO dto = new VerifyCodePublishAbstractDTO();
        dto.setIpCount(ipCount);
        dto.setIpCountKey(ipCountKey);
        dto.setPublishCount(publishCount);
        dto.setPublishCountKey(publishCountKey);
        dto.setVerifyCodeKey(verifyCodeKey);
        dto.setVerifyCode(VerifyCodeUtil.getVerifyCode());
        return dto;
    }

    public void publishAfter(VerifyCodePublishAbstractDTO dto) {
        // 缓存验证码到缓存中
        this.redisCache.set(dto.getVerifyCodeKey(), dto.getVerifyCode(), 60 * 3, TimeUnit.SECONDS);

        // 验证码（ip && account）发送次数递增，24小时 与 3小时
        this.redisCache.set(dto.getIpCountKey(), String.valueOf(dto.getIpCount() + 1), 24, TimeUnit.HOURS);
        this.redisCache.set(dto.getPublishCountKey(), String.valueOf(dto.getPublishCount() + 1), 3, TimeUnit.HOURS);
    }

}
